package factories

import (
	"context"
	"encoding/json"
	"sync"
	"time"

	"hyper/supports/logger"
	"hyper/supports/queue/abstruct"

	"github.com/redis/go-redis/v9"

	redis2 "hyper/supports/redis"
)

// 定义 redis 结构体
type RedisQueue struct {
	redis    *redis.Client
	Data     *abstruct.QueueObj
	JsonData string
	QueueCh  chan string
}

// 消费者回调方法
type RedisConsumer func(key string)

// 实例化对象
func (r *RedisQueue) New(obj *abstruct.QueueObj) *RedisQueue {

	// 队列参数赋值
	r.Data = obj

	return r
}

// 将结构体转为Json
func (r *RedisQueue) MakeJson() *RedisQueue {
	// 获取格式化后得 json 字符串
	jsonStr, err := json.Marshal(r.Data)
	if err != nil {
		logger.Error(map[string]any{
			"err":     err,
			"data":    r.Data,
			"jsonStr": jsonStr,
			"message": "转换json 字符串失败",
		})
	}

	r.JsonData = string(jsonStr)

	// 获取队列名称
	r.Data.Name = abstruct.QueueName(r.Data.Name)

	return r
}

// 压入队列 并返回结果 生产者
func (r *RedisQueue) Producer() error {

	err := redis2.Redis.Client.RPush(context.Background(), r.Data.Name, r.JsonData).Err()

	return err
}

// 消费者代码
func (r *RedisQueue) Consumer(fn RedisConsumer) {

	result, err := redis2.Redis.Client.RPopLPush(context.Background(), abstruct.QueueName(r.Data.Name), "processing_queue").Result()

	// 如果队列不存在 则休眠 休眠之后跳出当前次循环 再次执行
	if err == redis.Nil {
		time.Sleep(abstruct.SleepTime)
	}
	// 读取队列错误
	if err != nil {
		logger.Error(map[string]any{
			"err":     err,
			"message": "读取队列错误",
			"data":    r.Data,
			"queue":   r.Data.Name,
			"name":    r.Data.Name,
		})
	}

	var wg sync.WaitGroup

	// 确认
	err = redis2.Redis.Client.LRem(context.Background(), "processing_queue", 0, result).Err()

	if err == nil {
		wg.Add(1)

		// 处理消息
		fn(result)
	} else if err == redis.Nil {
		logger.Info(map[string]any{
			"err":     err,
			"message": "Queue is empty, waiting...",
		})
		time.Sleep(abstruct.SleepTime)
	}

	// 任务执行间隔
	time.Sleep(time.Microsecond * 500)

	wg.Wait()
}
